﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using VulnDBExplorer.Services;
using System.Collections;
using System.Diagnostics;
using Luna;

namespace VulnDB.Action.DataCollectors.Services.CodeAge {
	
	class SourceFileProfile : ISourceFileProfile{

		public static readonly Regex CvsAnnotatedLine = new Regex(@"(\d+(\.\d+)+)", RegexOptions.Multiline);
		private Dictionary<string, SourceFileRevision> revisions;
		private string activeFile;

		public SourceFileProfile(string filename, string activeFile = null) {
			this.Filename = filename;
			this.activeFile = activeFile;
			revisions = new Dictionary<string, SourceFileRevision>();
		}

		public string Filename { get; private set; }

		public string ActiveFilename {
			get { return string.IsNullOrWhiteSpace(activeFile) ? Filename : activeFile; }
			set { activeFile = value; }
		}

		public SourceFileRevision addLine(string revision, string author, DateTime age, int lineIdx) {
			SourceFileRevision rev = null;
			if (!revisions.TryGetValue(revision, out rev))
				revisions.Add(revision, rev = new SourceFileRevision(revision, author, age, null));
			rev.includeLine(lineIdx);
			return rev;
		}

		public void addRevision(SourceFileRevision rev) {
			revisions[rev.Revision] = rev;
		}

		public ISourceFileRevision this[string revision] {
			get { return revisions.defaultGet(revision); }
		}

		public IEnumerator<ISourceFileRevision> GetEnumerator() {
			return revisions.Values.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}
	}

	class SourceFileRevision : ISourceFileRevision {

		private List<FileCompareResult.FileChunk> lines;

		public SourceFileRevision() {
			lines = new List<FileCompareResult.FileChunk>();
		}

		public SourceFileRevision(string revision, string author, DateTime age, IList lines) {
			this.Revision = revision;
			this.Age = age;
			this.Author = author;
			this.lines = new List<FileCompareResult.FileChunk>();
			if (lines != null) {
				this.Count = lines.Count;
				SourceFileRevision.makeChunkList(lines, Lines);
			}
		}

		public static void test() {
			Debug.WriteLine("Hello tester");
			IList lines = "1 2 3 5 6 7 10 13 14 15 19 20".splitEx(' ').ToArray();
			List<FileCompareResult.FileChunk> chunks = new List<FileCompareResult.FileChunk>();
			makeChunkList(lines, chunks);
		}

		public void includeLine(int line) {
			int idx = Lines.Count - 1;
			FileCompareResult.FileChunk chunk = new FileCompareResult.FileChunk() { Begin = line, End = line };
			if (idx >= 0 && Lines[idx].End == line - 1)
				chunk.set(Lines[idx].Begin, line);
			else idx = -1;
			if (idx >= 0)
				Lines[idx] = chunk;
			else
				Lines.Add(chunk);
			Count++;
		}
		
		private static void makeChunkList(IList lines, IList<FileCompareResult.FileChunk> chunks) {
			if (lines.Count > 0) {
				int start = lines[0].ToString().toInt();
				int end = start;
				foreach (var item in lines) {
					int value = item.ToString().toInt();
					if (value == end || value == end + 1)
						end = value;
					else {
						FileCompareResult.FileChunk chunk = new FileCompareResult.FileChunk();
						chunk.Begin = start;
						chunk.End = end;
						chunks.Add(chunk);
						start = end = value;
					}
				}
				chunks.Add(new FileCompareResult.FileChunk() { Begin = start, End = end });
			}
		}

		public string Revision { get; private set; }

		public DateTime Age { get; private set; }

		public String Author { get; private set; }

		public int Count { get; internal set; }

		public IList<VulnDBExplorer.Services.FileCompareResult.FileChunk> Lines { get { return lines; } }

		public override string ToString() {
			return string.Format("{0},{1},{2},Line: {3} [{4}]", Revision, Author, Age, Count, this.GetType().Name);
		}

		public void consolidateLines() {
			lines.Sort((c1, c2) => c1.Begin - c2.Begin);
			for(int i = 0; i< lines.Count - 1; i++)
				if (lines[i].End == lines[i + 1].Begin) {
					lines[i] = new FileCompareResult.FileChunk() { Begin = lines[i].Begin, End = lines[i + 1].End };
					lines.RemoveAt(i + 1);
					i--;
				}
		}
	}
}
